﻿#pragma execution_character_set("utf-8")
#include "udpServer.h"
#include <QUdpSocket>
#include <QFile>
#include <QDir>
#include <QPushButton>
#include <QProcess>
#include <QThread>
#include <QTimer>
#include <QHostInfo>
static QFile* file = nullptr;
static QList<QNetworkDatagram> dataList;
static std::mutex mtx;
static std::condition_variable cv;
bool stop = false;
QString uiFileName;
static auto addressList=QHostInfo::fromName(QHostInfo::localHostName()).addresses();

// 处理接受到的数据
void dataProcess();

// 使用QThread, 需要重写run
class RecvProcess :public QThread {
    using QThread::QThread;
protected:
    virtual void run()override {
        dataProcess();
    }
};

UdpServer::UdpServer(QWidget* parent)
    : QWidget(parent), recThread(nullptr)
{
    ui.setupUi(this);

    initSocket();
    initUI();
    initThread();

}

UdpServer::~UdpServer()
{
    stop = true;
    if(recThread)
        recThread->wait();
    delete file;
}

inline void UdpServer::initUI()
{
    auto timer = new QTimer(this);
    connect(timer, &QTimer::timeout, [this] {
        ui.label->setText(uiFileName);
    });
    timer->start(100);
    connect(ui.pushButton, &QAbstractButton::clicked, [this] {
        QProcess::execute("explorer recvFile");
    });
}

inline void UdpServer::initSocket()
{
    udpSocket = new QUdpSocket(this);
    udpSocket->bind(16001, QAbstractSocket::DontShareAddress);
    udpSocket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption, 1024 * 1024);
    connect(udpSocket, &QAbstractSocket::readyRead, this, &UdpServer::readSocket);
}

void UdpServer::readSocket()
{
    while (udpSocket->hasPendingDatagrams()) {
        std::unique_lock<std::mutex> lock(mtx);
        dataList.append(udpSocket->receiveDatagram());
        cv.notify_one();
    }
}


inline void UdpServer::initThread()
{
#if 0 // 使用QThread, 需要自定义类,重写run
    recThread = new RecvProcess(this);
    recThread->start();
#else	// 使用标准库
    std::thread t1(dataProcess);
    t1.detach();
#endif
}

void dataProcess()
{
    while (!stop) {
        QNetworkDatagram datagram;
        {
            std::unique_lock<std::mutex> lock(mtx);
            cv.wait(lock, [] {return !dataList.isEmpty(); });
            datagram = dataList.takeFirst();
        }

        QByteArray ba = datagram.data();
        QHostAddress sender = datagram.senderAddress();
        quint16 senderPort = datagram.senderPort();

        unsigned int fileNameLen = 0;   // 文件名长度
        fileNameLen = (ba[3] & 0xff);
        fileNameLen = (ba[2] & 0xff) + (fileNameLen << 8);
        fileNameLen = (ba[1] & 0xff) + (fileNameLen << 8);
        fileNameLen = (ba[0] & 0xff) + (fileNameLen << 8);

        int ISN;    // 报文序列号
        ISN = (ba[3 + fileNameLen + 4] & 0xff);
        ISN = (ba[2 + fileNameLen + 4] & 0xff) + (ISN << 8);
        ISN = (ba[1 + fileNameLen + 4] & 0xff) + (ISN << 8);
        ISN = (ba[0 + fileNameLen + 4] & 0xff) + (ISN << 8);
        QString recvFileName = QString::fromUtf8(ba.data() + 4, fileNameLen);

        if (!file) {// 新文件传输进来
            // 创建文件夹
            QDir dir("recvFile");
            if (!dir.exists())
            {
                dir.cdUp();
                dir.mkdir("recvFile");
            }
            file = new QFile;
            file->setFileName("./recvFile/" + recvFileName.split("/").last());

            uiFileName = file->fileName();

            if (file->exists())
                qDebug() << "覆盖原有文件 " << file->fileName();
            file->open(QIODevice::WriteOnly);
        }
        if (file && file->isOpen()) {// 写入文件内容
            if (ISN == 0)
            {// 当前文件传输结束
                file->close();
                delete file;
                file = nullptr;
            }
            else
             file->write(ba.data() + 8 + fileNameLen, ba.size() - 8 - fileNameLen);
        }

    }
}
